# $Header: /mount/cvs-repository/Aligner/lib/perl/packs/Cpp.pm,v 1.1 2007/10/08 09:26:03 schweitz Exp $
package Cpp;

=head1 NAME

Cpp --- Parse code for the C/C++ pre-processor

=cut

sub new {
    my $class = shift;
    my $this = {
	'stack' => [],
    };
    bless $this, $class;
}

sub DESTROY ($) {
    my $this = shift;
}

sub GetStatus {
    my $this = shift;
    my @tmp = @{$this->{stack}};
    return join(' && ', @{$this->{stack}});
}

sub Parse {
    my $this = shift;
    my(@lines) = @_;
    my($line);

    foreach $line (@lines) {
	if ($line !~ /^\#/) {
	    print STDERR "ERROR: following line is not a text for the cpp\n";
	    print STDERR "$line\n";
	    next;
	}
	$this->_parse_line($line);
    }
}

sub _parse_line {
    my $this = shift;
    my($tok, $line) = $this->_get_token($_[0]);

    #print STDERR "_parse_line $tok, $line\n";
    if ($tok ne '#') {
	return 0;
    } 
    ($tok, $line) = $this->_get_token($line);
    if ($tok eq 'if') {
	return $this->_parse_if($line);
    } elsif ($tok eq 'ifdef') {
	return $this->_parse_ifdef($line);
    } elsif ($tok eq 'ifndef') {
	return $this->_parse_ifndef($line);
    } elsif ($tok eq 'else') {
	return $this->_parse_else($line);
    } elsif ($tok eq 'endif') {
	return $this->_parse_endif($line);
    } else {
	return 0;
    }
}

sub _parse_defined {
    my $this = shift;
    my($tok, $line) = $this->_get_token(shift);
}

sub _parse_if {
    my $this = shift;

    $this->_push(shift);

    return 1;
}

sub _parse_ifdef {
    my $this = shift;
    my($tok, $line) = $this->_get_token(shift);
    if (length($tok) <= 0) {
	print STDERR "Argument for the #ifdef is missing\n";
	return 0;
    }
    if ($tok !~ /^_/) {    # special condition for the comment2tex
	$this->_push('defined(' . $tok . ')');
    }
    return 1;
}

sub _parse_ifndef {
    my $this = shift;
    my($tok, $line) = $this->_get_token(shift);
    if (length($tok) <= 0) {
	print STDERR "Argument for the #ifndef is missing\n";
	return 0;
    }
    if ($tok !~ /^_/) {    # special condition for the comment2tex
	$this->_push('!' . 'defined(' . $tok . ')');
    }
    return 1;
}

sub _parse_else {
    my $this = shift;

    if ($this->_is_empty()) {
	print STDERR "extra #else\n";
	return 0;
    }
    my $tok = $this->_pop();
    if ($tok =~ /^!/) {
	$this->_push(substr($tok, 1));
    } else {
	$this->_push('!' . $tok);
    }
    return 1;
}

sub _parse_endif {
    my $this = shift;

    if ($this->_is_empty()) {
	print STDERR "extra #endif\n";
	return 0;
    }
    my $tok = $this->_pop();
    return 1;
}

sub _push {
    my $this = shift;
    push(@{$this->{stack}}, shift);
}

sub _pop {
    my $this = shift;
    pop(@{$this->{stack}});
}

sub _is_empty {
    my $this = shift;
    return length(@{$this->{stack}}) <= 0;
}

sub _get_token {
    my $this = shift;
    my($line) = shift;
    my($tok);

    #print STDERR "GETTOKEN: - : $line \n";
    $line =~ s/^\s+//g;
    if ($line =~ /^(\w+)(.*)/) {
	$tok = $1;
	$line = $2;
    } else {
	$tok = substr($line, 0, 1);
	$line = substr($line, 1);
    }
    #print STDERR "GETTOKEN: $tok : $line \n";
    return ($tok, $line);
}

1;
